home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / src / filesubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  13.8 KB  |  663 lines

  1. /* filesubr.c --- subroutines for dealing with files
  2.    Jim Blandy <jimb@cyclic.com>
  3.  
  4.    This file is part of GNU CVS.
  5.  
  6.    GNU CVS is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by the
  8.    Free Software Foundation; either version 2, or (at your option) any
  9.    later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* These functions were moved out of subr.c because they need different
  21.    definitions under operating systems (like, say, Windows NT) with different
  22.    file system semantics.  */
  23.  
  24. #include "cvs.h"
  25.  
  26. /*
  27.  * I don't know of a convenient way to test this at configure time, or else
  28.  * I'd certainly do it there.
  29.  */
  30. #if defined(NeXT)
  31. #define LOSING_TMPNAM_FUNCTION
  32. #endif
  33.  
  34. static int deep_remove_dir PROTO((const char *path));
  35.  
  36. /*
  37.  * Copies "from" to "to".
  38.  */
  39. void
  40. copy_file (from, to)
  41.     const char *from;
  42.     const char *to;
  43. {
  44.     struct stat sb;
  45.     struct utimbuf t;
  46.     int fdin, fdout;
  47.  
  48.     if (trace)
  49. #ifdef SERVER_SUPPORT
  50.     (void) fprintf (stderr, "%c-> copy(%s,%s)\n",
  51.             (server_active) ? 'S' : ' ', from, to);
  52. #else
  53.     (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to);
  54. #endif
  55.     if (noexec)
  56.     return;
  57.  
  58.     if ((fdin = open (from, O_RDONLY)) < 0)
  59.     error (1, errno, "cannot open %s for copying", from);
  60.     if (fstat (fdin, &sb) < 0)
  61.     error (1, errno, "cannot fstat %s", from);
  62.     if ((fdout = creat (to, (int) sb.st_mode & 07777)) < 0)
  63.     error (1, errno, "cannot create %s for copying", to);
  64.     if (sb.st_size > 0)
  65.     {
  66.     char buf[BUFSIZ];
  67.     int n;
  68.  
  69.     for (;;) 
  70.     {
  71.         n = read (fdin, buf, sizeof(buf));
  72.         if (n == -1)
  73.         {
  74. #ifdef EINTR
  75.         if (errno == EINTR)
  76.             continue;
  77. #endif
  78.         error (1, errno, "cannot read file %s for copying", from);
  79.         }
  80.             else if (n == 0) 
  81.         break;
  82.   
  83.         if (write(fdout, buf, n) != n) {
  84.         error (1, errno, "cannot write file %s for copying", to);
  85.         }
  86.     }
  87.  
  88. #ifdef HAVE_FSYNC
  89.     if (fsync (fdout)) 
  90.         error (1, errno, "cannot fsync file %s after copying", to);
  91. #endif
  92.     }
  93.  
  94.     if (close (fdin) < 0) 
  95.     error (0, errno, "cannot close %s", from);
  96.     if (close (fdout) < 0)
  97.     error (1, errno, "cannot close %s", to);
  98.  
  99.     /* now, set the times for the copied file to match those of the original */
  100.     memset ((char *) &t, 0, sizeof (t));
  101.     t.actime = sb.st_atime;
  102.     t.modtime = sb.st_mtime;
  103.     (void) utime (to, &t);
  104. }
  105.  
  106. /* FIXME-krp: these functions would benefit from caching the char * &
  107.    stat buf.  */
  108.  
  109. /*
  110.  * Returns non-zero if the argument file is a directory, or is a symbolic
  111.  * link which points to a directory.
  112.  */
  113. int
  114. isdir (file)
  115.     const char *file;
  116. {
  117.     struct stat sb;
  118.  
  119.     if (stat (file, &sb) < 0)
  120.     return (0);
  121.     return (S_ISDIR (sb.st_mode));
  122. }
  123.  
  124. /*
  125.  * Returns non-zero if the argument file is a symbolic link.
  126.  */
  127. int
  128. islink (file)
  129.     const char *file;
  130. {
  131. #ifdef S_ISLNK
  132.     struct stat sb;
  133.  
  134.     if (lstat (file, &sb) < 0)
  135.     return (0);
  136.     return (S_ISLNK (sb.st_mode));
  137. #else
  138.     return (0);
  139. #endif
  140. }
  141.  
  142. /*
  143.  * Returns non-zero if the argument file exists.
  144.  */
  145. int
  146. isfile (file)
  147.     const char *file;
  148. {
  149.     return isaccessible(file, F_OK);
  150. }
  151.  
  152. /*
  153.  * Returns non-zero if the argument file is readable.
  154.  */
  155. int
  156. isreadable (file)
  157.     const char *file;
  158. {
  159.     return isaccessible(file, R_OK);
  160. }
  161.  
  162. /*
  163.  * Returns non-zero if the argument file is writable.
  164.  */
  165. int
  166. iswritable (file)
  167.     const char *file;
  168. {
  169.     return isaccessible(file, W_OK);
  170. }
  171.  
  172. /*
  173.  * Returns non-zero if the argument file is accessable according to
  174.  * mode.  If compiled with SETXID_SUPPORT also works if cvs has setxid
  175.  * bits set.
  176.  */
  177. int
  178. isaccessible (file, mode)
  179.     const char *file;
  180.     const int mode;
  181. {
  182. #ifdef SETXID_SUPPORT
  183.     struct stat sb;
  184.     int umask = 0;
  185.     int gmask = 0;
  186.     int omask = 0;
  187.     int uid;
  188.     
  189.     if (stat(file, &sb) == -1)
  190.     return 0;
  191.     if (mode == F_OK)
  192.     return 1;
  193.  
  194.     uid = geteuid();
  195.     if (uid == 0)        /* superuser */
  196.     {
  197.     if (mode & X_OK)
  198.         return sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH);
  199.     else
  200.         return 1;
  201.     }
  202.     
  203.     if (mode & R_OK)
  204.     {
  205.     umask |= S_IRUSR;
  206.     gmask |= S_IRGRP;
  207.     omask |= S_IROTH;
  208.     }
  209.     if (mode & W_OK)
  210.     {
  211.     umask |= S_IWUSR;
  212.     gmask |= S_IWGRP;
  213.     omask |= S_IWOTH;
  214.     }
  215.     if (mode & X_OK)
  216.     {
  217.     umask |= S_IXUSR;
  218.     gmask |= S_IXGRP;
  219.     omask |= S_IXOTH;
  220.     }
  221.  
  222.     if (sb.st_uid == uid)
  223.     return (sb.st_mode & umask) == umask;
  224.     else if (sb.st_gid == getegid())
  225.     return (sb.st_mode & gmask) == gmask;
  226.     else
  227.     return (sb.st_mode & omask) == omask;
  228. #else
  229.     return access(file, mode) == 0;
  230. #endif
  231. }
  232.  
  233. /*
  234.  * Open a file and die if it fails
  235.  */
  236. FILE *
  237. open_file (name, mode)
  238.     const char *name;
  239.     const char *mode;
  240. {
  241.     FILE *fp;
  242.  
  243.     if ((fp = fopen (name, mode)) == NULL)
  244.     error (1, errno, "cannot open %s", name);
  245.     return (fp);
  246. }
  247.  
  248. /*
  249.  * Make a directory and die if it fails
  250.  */
  251. void
  252. make_directory (name)
  253.     const char *name;
  254. {
  255.     struct stat sb;
  256.  
  257.     if (stat (name, &sb) == 0 && (!S_ISDIR (sb.st_mode)))
  258.         error (0, 0, "%s already exists but is not a directory", name);
  259.     if (!noexec && mkdir (name, 0777) < 0)
  260.     error (1, errno, "cannot make directory %s", name);
  261. }
  262.  
  263. /*
  264.  * Make a path to the argument directory, printing a message if something
  265.  * goes wrong.
  266.  */
  267. void
  268. make_directories (name)
  269.     const char *name;
  270. {
  271.     char *cp;
  272.  
  273.     if (noexec)
  274.     return;
  275.  
  276.     if (mkdir (name, 0777) == 0 || errno == EEXIST)
  277.     return;
  278.     if (! existence_error (errno))
  279.     {
  280.     error (0, errno, "cannot make path to %s", name);
  281.     return;
  282.     }
  283.     if ((cp = strrchr (name, '/')) == NULL)
  284.     return;
  285.     *cp = '\0';
  286.     make_directories (name);
  287.     *cp++ = '/';
  288.     if (*cp == '\0')
  289.     return;
  290.     (void) mkdir (name, 0777);
  291. }
  292.  
  293. /*
  294.  * Change the mode of a file, either adding write permissions, or removing
  295.  * all write permissions.  Either change honors the current umask setting.
  296.  */
  297. void
  298. xchmod (fname, writable)
  299.     char *fname;
  300.     int writable;
  301. {
  302.     struct stat sb;
  303.     mode_t mode, oumask;
  304.  
  305.     if (stat (fname, &sb) < 0)
  306.     {
  307.     if (!noexec)
  308.         error (0, errno, "cannot stat %s", fname);
  309.     return;
  310.     }
  311.     oumask = umask (0);
  312.     (void) umask (oumask);
  313.     if (writable)
  314.     {
  315.     mode = sb.st_mode | (~oumask
  316.                  & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
  317.                 | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
  318.                 | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
  319.     }
  320.     else
  321.     {
  322.     mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
  323.     }
  324.  
  325.     if (trace)
  326. #ifdef SERVER_SUPPORT
  327.     (void) fprintf (stderr, "%c-> chmod(%s,%o)\n",
  328.             (server_active) ? 'S' : ' ', fname,
  329.             (unsigned int) mode);
  330. #else
  331.     (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname,
  332.             (unsigned int) mode);
  333. #endif
  334.     if (noexec)
  335.     return;
  336.  
  337.     if (chmod (fname, mode) < 0)
  338.     error (0, errno, "cannot change mode of file %s", fname);
  339. }
  340.  
  341. /*
  342.  * Rename a file and die if it fails
  343.  */
  344. void
  345. rename_file (from, to)
  346.     const char *from;
  347.     const char *to;
  348. {
  349.     if (trace)
  350. #ifdef SERVER_SUPPORT
  351.     (void) fprintf (stderr, "%c-> rename(%s,%s)\n",
  352.             (server_active) ? 'S' : ' ', from, to);
  353. #else
  354.     (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to);
  355. #endif
  356.     if (noexec)
  357.     return;
  358.  
  359.     if (rename (from, to) < 0)
  360.     error (1, errno, "cannot rename file %s to %s", from, to);
  361. }
  362.  
  363. /*
  364.  * link a file, if possible.  Warning: the Windows NT version of this
  365.  * function just copies the file, so only use this function in ways
  366.  * that can deal with either a link or a copy.
  367.  */
  368. int
  369. link_file (from, to)
  370.     const char *from;
  371.     const char *to;
  372. {
  373.     if (trace)
  374. #ifdef SERVER_SUPPORT
  375.     (void) fprintf (stderr, "%c-> link(%s,%s)\n",
  376.             (server_active) ? 'S' : ' ', from, to);
  377. #else
  378.     (void) fprintf (stderr, "-> link(%s,%s)\n", from, to);
  379. #endif
  380.     if (noexec)
  381.     return (0);
  382.  
  383.     return (link (from, to));
  384. }
  385.  
  386. /*
  387.  * unlink a file, if possible.
  388.  */
  389. int
  390. unlink_file (f)
  391.     const char *f;
  392. {
  393.     if (trace)
  394. #ifdef SERVER_SUPPORT
  395.     (void) fprintf (stderr, "%c-> unlink(%s)\n",
  396.             (server_active) ? 'S' : ' ', f);
  397. #else
  398.     (void) fprintf (stderr, "-> unlink(%s)\n", f);
  399. #endif
  400.     if (noexec)
  401.     return (0);
  402.  
  403.     return (unlink (f));
  404. }
  405.  
  406. /*
  407.  * Unlink a file or dir, if possible.  If it is a directory do a deep
  408.  * removal of all of the files in the directory.  Return -1 on error
  409.  * (in which case errno is set).
  410.  */
  411. int
  412. unlink_file_dir (f)
  413.     const char *f;
  414. {
  415.     if (trace)
  416. #ifdef SERVER_SUPPORT
  417.     (void) fprintf (stderr, "%c-> unlink_file_dir(%s)\n",
  418.             (server_active) ? 'S' : ' ', f);
  419. #else
  420.     (void) fprintf (stderr, "-> unlink_file_dir(%s)\n", f);
  421. #endif
  422.     if (noexec)
  423.     return (0);
  424.  
  425.     /* For at least some unices, if root tries to unlink() a directory,
  426.        instead of doing something rational like returning EISDIR,
  427.        the system will gleefully go ahead and corrupt the filesystem.
  428.        So we first call isdir() to see if it is OK to call unlink().  This
  429.        doesn't quite work--if someone creates a directory between the
  430.        call to isdir() and the call to unlink(), we'll still corrupt
  431.        the filesystem.  Where is the Unix Haters Handbook when you need
  432.        it?  */
  433.     if (isdir(f)) 
  434.     return deep_remove_dir(f);
  435.     else
  436.     {
  437.     if (unlink (f) != 0)
  438.         return -1;
  439.     }
  440.     /* We were able to remove the file from the disk */
  441.     return 0;
  442. }
  443.  
  444. /* Remove a directory and everything it contains.  Returns 0 for
  445.  * success, -1 for failure (in which case errno is set).
  446.  */
  447.  
  448. static int
  449. deep_remove_dir (path)
  450.     const char *path;
  451. {
  452.     DIR          *dirp;
  453.     struct dirent *dp;
  454.     char       buf[PATH_MAX];
  455.  
  456.     if (rmdir (path) != 0 && (errno == ENOTEMPTY || errno == EEXIST)) 
  457.     {
  458.     if ((dirp = opendir (path)) == NULL)
  459.         /* If unable to open the directory return
  460.          * an error
  461.          */
  462.         return -1;
  463.  
  464.     while ((dp = readdir (dirp)) != NULL)
  465.     {
  466.         if (strcmp (dp->d_name, ".") == 0 ||
  467.             strcmp (dp->d_name, "..") == 0)
  468.         continue;
  469.  
  470.         sprintf (buf, "%s/%s", path, dp->d_name);
  471.  
  472.         /* See comment in unlink_file_dir explanation of why we use
  473.            isdir instead of just calling unlink and checking the
  474.            status.  */
  475.         if (isdir(buf)) 
  476.         {
  477.         if (deep_remove_dir(buf))
  478.         {
  479.             closedir(dirp);
  480.             return -1;
  481.         }
  482.         }
  483.         else
  484.         {
  485.         if (unlink (buf) != 0)
  486.         {
  487.             closedir(dirp);
  488.             return -1;
  489.         }
  490.         }
  491.     }
  492.     closedir (dirp);
  493.     return rmdir (path);
  494.     }
  495.  
  496.     /* Was able to remove the directory return 0 */
  497.     return 0;
  498. }
  499.  
  500. /* Read NCHARS bytes from descriptor FD into BUF.
  501.    Return the number of characters successfully read.
  502.    The number returned is always NCHARS unless end-of-file or error.  */
  503. static size_t
  504. block_read (fd, buf, nchars)
  505.     int fd;
  506.     char *buf;
  507.     size_t nchars;
  508. {
  509.     char *bp = buf;
  510.     size_t nread;
  511.  
  512.     do 
  513.     {
  514.     nread = read (fd, bp, nchars);
  515.     if (nread == (size_t)-1)
  516.     {
  517. #ifdef EINTR
  518.         if (errno == EINTR)
  519.         continue;
  520. #endif
  521.         return (size_t)-1;
  522.     }
  523.  
  524.     if (nread == 0)
  525.         break; 
  526.  
  527.     bp += nread;
  528.     nchars -= nread;
  529.     } while (nchars != 0);
  530.  
  531.     return bp - buf;
  532.  
  533.     
  534. /*
  535.  * Compare "file1" to "file2". Return non-zero if they don't compare exactly.
  536.  */
  537. int
  538. xcmp (file1, file2)
  539.     const char *file1;
  540.     const char *file2;
  541. {
  542.     char *buf1, *buf2;
  543.     struct stat sb1, sb2;
  544.     int fd1, fd2;
  545.     int ret;
  546.  
  547.     if ((fd1 = open (file1, O_RDONLY)) < 0)
  548.     error (1, errno, "cannot open file %s for comparing", file1);
  549.     if ((fd2 = open (file2, O_RDONLY)) < 0)
  550.     error (1, errno, "cannot open file %s for comparing", file2);
  551.     if (fstat (fd1, &sb1) < 0)
  552.     error (1, errno, "cannot fstat %s", file1);
  553.     if (fstat (fd2, &sb2) < 0)
  554.     error (1, errno, "cannot fstat %s", file2);
  555.  
  556.     /* A generic file compare routine might compare st_dev & st_ino here 
  557.        to see if the two files being compared are actually the same file.
  558.        But that won't happen in CVS, so we won't bother. */
  559.  
  560.     if (sb1.st_size != sb2.st_size)
  561.     ret = 1;
  562.     else if (sb1.st_size == 0)
  563.     ret = 0;
  564.     else
  565.     {
  566.     /* FIXME: compute the optimal buffer size by computing the least
  567.        common multiple of the files st_blocks field */
  568.     size_t buf_size = 8 * 1024;
  569.     size_t read1;
  570.     size_t read2;
  571.  
  572.     buf1 = xmalloc (buf_size);
  573.     buf2 = xmalloc (buf_size);
  574.  
  575.     do 
  576.     {
  577.         read1 = block_read (fd1, buf1, buf_size);
  578.         if (read1 == (size_t)-1)
  579.         error (1, errno, "cannot read file %s for comparing", file1);
  580.  
  581.         read2 = block_read (fd2, buf2, buf_size);
  582.         if (read2 == (size_t)-1)
  583.         error (1, errno, "cannot read file %s for comparing", file2);
  584.  
  585.         /* assert (read1 == read2); */
  586.  
  587.         ret = memcmp(buf1, buf2, read1);
  588.     } while (ret == 0 && read1 == buf_size);
  589.  
  590.     free (buf1);
  591.     free (buf2);
  592.     }
  593.     
  594.     (void) close (fd1);
  595.     (void) close (fd2);
  596.     return (ret);
  597. }
  598.  
  599. #ifdef LOSING_TMPNAM_FUNCTION
  600. char *tmpnam(char *s)
  601. {
  602.     static char value[L_tmpnam+1];
  603.  
  604.     if (s){
  605.        strcpy(s,"/tmp/cvsXXXXXX");
  606.        mktemp(s);
  607.        return s;
  608.     }else{
  609.        strcpy(value,"/tmp/cvsXXXXXX");
  610.        mktemp(s);
  611.        return value;
  612.     }
  613. }
  614. #endif
  615.  
  616. /* Return non-zero iff FILENAME is absolute.
  617.    Trivial under Unix, but more complicated under other systems.  */
  618. int
  619. isabsolute (filename)
  620.     const char *filename;
  621. {
  622.     return filename[0] == '/';
  623. }
  624.  
  625.  
  626. /* Return a pointer into PATH's last component.  */
  627. char *
  628. last_component (path)
  629.     char *path;
  630. {
  631.     char *last = strrchr (path, '/');
  632.  
  633.     if (last)
  634.         return last + 1;
  635.     else
  636.         return path;
  637. }
  638.  
  639. /* Return the home directory.  Returns a pointer to storage
  640.    managed by this function or its callees (currently getenv).  */
  641. char *
  642. get_homedir ()
  643. {
  644.     return getenv ("HOME");
  645. }
  646.  
  647. /* See cvs.h for description.  On unix this does nothing, because the
  648.    shell expands the wildcards.  */
  649. void
  650. expand_wild (argc, argv, pargc, pargv)
  651.     int argc;
  652.     char **argv;
  653.     int *pargc;
  654.     char ***pargv;
  655. {
  656.     int i;
  657.     *pargc = argc;
  658.     *pargv = (char **) xmalloc (argc * sizeof (char *));
  659.     for (i = 0; i < argc; ++i)
  660.     (*pargv)[i] = xstrdup (argv[i]);
  661. }
  662.